package com.flute.icrawler.framework.autoadjust;

import com.flute.tools.timer.IntervalExecutor;
import com.flute.tools.util.collection.InstanceAccumulator;
import com.flute.icrawler.app.processor.AbstractProcessor;
import com.flute.icrawler.framework.executor.ExecutorMananger;
import com.flute.icrawler.framework.executor.MultiThreadProcessor;
import com.flute.icrawler.framework.executor.ProcessorExecutor;
import com.flute.icrawler.framework.framework.LocalCrawlUrlPool;

public class ExecutorAdjuster implements IAdjuster {
	private LocalCrawlUrlPool processPool;
	private ExecutorMananger manager;
	private IntervalExecutor adjustExecutor;
	private InstanceAccumulator accumulator;

	public ExecutorAdjuster(LocalCrawlUrlPool processPool,
			ExecutorMananger manager) {
		this.processPool = processPool;
		this.manager = manager;
		this.accumulator = new InstanceAccumulator();
		this.adjustExecutor = getAdjustExecutor();
		this.adjustExecutor.setName("Adjust Processor Thread");
	}

	@Override
	public void setInterval(int ms) {
		adjustExecutor.setInterval(ms);
	}

	@Override
	public void run() {
		adjustExecutor.setInterval(1000);
		adjustExecutor.start();
	}

	private IntervalExecutor getAdjustExecutor() {
		return new IntervalExecutor() {
			private int count = 0;
			private static final int TIMES = 1;

			private static final int FREE_LOWER_BOUND = 5;
			private static final int FREE_UPPER_BOUND = 10;

			/*
			 * 每隔interval毫秒自动记录一次状态，以TIMES次数的记录的平均值作为状态值。
			 * 如果有少于百分比为FREE_LOWER_BOUND的空闲操作则说明processor处于满负荷状态，增加更多的processor；
			 * 如果有大于百分比为FREE_UPPER_BOUND的空闲操作则说明processor处于空闲状态，减少的processor的个数。
			 * 
			 * 计算公式：空闲操作百分比= interval时间内的空闲操作数 * 空闲操作所需时间 *100 / 线程数 / interval
			 * 
			 * @see com.cpkf.yyjd.tools.timer.IntervalExecutor#execute()
			 */
			@Override
			public void execute() {
				if (count < TIMES) {
					InstanceAccumulator recored = processPool
							.getFreeProcessorAccumulator();
					for (Object processor : recored.getKeys()) {
						for (int i = 0; i < recored.getCount(processor); i++) {
							accumulator.addKey(processor);
						}
					}
					count++;
				} else {
					for (AbstractProcessor processor : manager.getProcessors()) {
						int processFreeCount = processPool
								.getFreeProcessorAccumulator().getCount(
										processor);
						int freeTime = processFreeCount
								* MultiThreadProcessor.SLEEP_INTERVAL / TIMES;
						ProcessorExecutor processorExecutor = manager
								.getProcessorExecutor(processor);
						int processCount = processorExecutor.getCount();
						if (processCount > 0) {
							freeTime = freeTime / processCount;
						}

						freeTime = freeTime * 100
								/ adjustExecutor.getInterval();
						if (freeTime > FREE_UPPER_BOUND) {
							processorExecutor.decrease();
						} else if (freeTime < FREE_LOWER_BOUND
								&& !processPool.isDone()) {
							processorExecutor.increase();
						}

					}
					accumulator.clear();
					count = 0;
				}
			}

		};
	}

	public void setFinished(boolean isFinished) {
		adjustExecutor.setFinish(isFinished);
	}
}
